package com.artfii;

import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 简单 ID 生成
 * 方案：长度 = "yyMMddHHmmssSSS"(15) + 原子顺序数累加(位长自定义)
 * long类型最大为19位,足于应付普通需求
 * Created by ${leeton} on 2018/11/21.
 */
public enum IdGen {
    ONLY;

    private BigInteger lastId = BigInteger.valueOf(0); //上次生成ID的时间截
    private int last_atomic_num = 0; //上次的顺序数
    private static final AtomicInteger atomicNum = new AtomicInteger();
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmssSSS");//(15)位

    //原子顺序数长度(即是每毫秒后最多可以生成的顺序号的数量)
    public static final int atomic_num_two = 99;
    public static final int atomic_num_three = 999;
    public static final int atomic_num_four = 9999;
    public static final int atomic_num_five = 99999;

    private StringBuffer getYmdId() {
        return new StringBuffer(sdf.format(System.currentTimeMillis()));
    }

    /**
     * 生成默认ID
     *
     * @return 19位 Long 型ID
     */
    public long getDefId() {
        return IdGen.ONLY.id(atomic_num_four).longValue();
    }

    public synchronized BigInteger id(int longs) {
        if (last_atomic_num != longs) { // 上次运行时定义的顺序数长度与本次不同
            lastId = BigInteger.valueOf(0);
        }
        //数字长度为longs位，长度不够数字前面补0
        String format = "%0" + Integer.valueOf(longs).toString().length() + "d";
        StringBuffer ymd = getYmdId();
        BigInteger currentId = getCurrentId(ymd, longs, format);
        while (currentId.compareTo(lastId) <= 0) {
            ymd = getYmdId();
            currentId = getCurrentId(ymd, longs, format);
        }

        //上次生成ID的时间截
        lastId = currentId;
        last_atomic_num = longs;
        return currentId;
    }

    private BigInteger getCurrentId(StringBuffer lastYmd, int longs, String format) {
        return new BigInteger(lastYmd.append(getNewAutoNum(longs, format)).toString());
    }

    /**
     * 生成原子顺序数字
     *
     * @param longs 原子顺序数的长度
     * @return
     */
    private String getNewAutoNum(int longs, String format) {
        int newNum = atomicNum.incrementAndGet();
        if (atomicNum.get() > longs) {//重置顺序号为 0
            atomicNum.set(0);
            newNum = atomicNum.get();
        }
        String newStrNum = String.format(format, newNum);
        return newStrNum;
    }

    public static void main(String[] args) {
   /*     for (int i = 0; i < 100; i++) {
            String idStr = String.valueOf(IdGen.ONLY.id(atomic_num_five));
            System.err.println(idStr);
            String ymd = idStr.substring(0, 17);
            System.err.println(sdf.format(System.currentTimeMillis()).equals(ymd));
        }

        System.err.println("19len="+IdGen.ONLY.getDefId());*/

        // 检查生成的 ID 是否递增的
        long start = System.currentTimeMillis();
        final int NUMS = 1_000_000;
        List<Long> idList = new ArrayList<>(NUMS);
        for (int i = 0; i < NUMS; i++) {
            long id = IdGen.ONLY.getDefId();
            idList.add(id);
            if (i > 0 && id <= idList.get(i - 1)) {
                System.err.println("ID 非递增！");
            }
        }
        long end = System.currentTimeMillis();
        System.err.println("use times ms:" + (end - start));
        System.err.println("每毫秒生成 ID:" + idList.size() / (end - start));

    }
}